// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CollectionValidate.cs" company="CSLib.Net Team">
//   Copyright (c) Roman "4ux-nbIx" Novitsky 2010
// </copyright>
// <summary>
//   Contains collection validation methods.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace CSLib.Net.Diagnostics
{
  #region Namespace Imports

  using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.Globalization;
  using System.Linq;

  using Annotations;

  #endregion


  /// <summary>
  /// Contains collection validation methods.
  /// </summary>
  [DebuggerStepThrough]
  [DebuggerNonUserCode]
  [UsedImplicitly(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.WithMembers)]
  public static class CollectionValidate
  {
    #region Public Methods

    /// <summary>
    /// Validates that the specified collection is empty.
    /// </summary>
    /// <typeparam name="TItem">
    /// The type of the item.
    /// </typeparam>
    /// <param name="collection">
    /// The collection to validate.
    /// </param>
    /// <param name="messageFormat">
    /// A composite format <see cref="string"/>.
    /// </param>
    /// <param name="messageArguments">
    /// An array of message arguments to format.
    /// </param>
    /// <exception cref="InvalidOperationException">
    /// <c>Invalid Operation Exception</c>.
    /// </exception>
    [StringFormatMethod("messageFormat")]
    public static void IsEmpty<TItem>(
      [NotNull] IEnumerable<TItem> collection, 
      [NotNull] string messageFormat, 
      [CanBeNull] params object[] messageArguments)
    {
      Assert.ArgumentNotNull(collection, "collection");
      Assert.ArgumentNotNull(messageFormat, "messageFormat");

      if (!collection.Any())
      {
        return;
      }

      ThrowException(messageFormat, messageArguments);
    }


    /// <summary>
    /// Validates that the specified collection does not contain items defined by the predicate.
    /// </summary>
    /// <typeparam name="TItem">The type of the item.</typeparam>
    /// <param name="collection">The collection to validate.</param>
    /// <param name="predicate">The predicate.</param>
    /// <param name="messageFormat">A composite format <see cref="string"/>.</param>
    /// <param name="messageArguments">An array of message arguments to format.</param>
    /// <exception cref="InvalidOperationException">
    /// <c>Invalid Operation Exception</c>.
    /// </exception>
    [StringFormatMethod("messageFormat")]
    public static void NotContains<TItem>(
      [NotNull] IEnumerable<TItem> collection, 
      [NotNull] Func<TItem, bool> predicate,
      [NotNull] string messageFormat,
      [CanBeNull] params object[] messageArguments)
    {
      Assert.ArgumentNotNull(collection, "collection");
      Assert.ArgumentNotNull(predicate, "predicate");
      Assert.ArgumentNotNull(messageFormat, "messageFormat");

      if (!collection.Any(predicate))
      {
        return;
      }

      ThrowException(messageFormat, messageArguments);
    }


    /// <summary>
    /// Validates that the specified collection contains items defined by the predicate.
    /// </summary>
    /// <typeparam name="TItem">The type of the item.</typeparam>
    /// <param name="collection">The collection to validate.</param>
    /// <param name="predicate">The predicate.</param>
    /// <param name="messageFormat">A composite format <see cref="string"/>.</param>
    /// <param name="messageArguments">An array of message arguments to format.</param>
    /// <exception cref="InvalidOperationException">
    /// <c>Invalid Operation Exception</c>.
    /// </exception>
    [StringFormatMethod("messageFormat")]
    public static void Contains<TItem>(
      [NotNull] IEnumerable<TItem> collection,
      [NotNull] Func<TItem, bool> predicate,
      [NotNull] string messageFormat,
      [CanBeNull] params object[] messageArguments)
    {
      Assert.ArgumentNotNull(collection, "collection");
      Assert.ArgumentNotNull(predicate, "predicate");
      Assert.ArgumentNotNull(messageFormat, "messageFormat");

      if (collection.Any(predicate))
      {
        return;
      }

      ThrowException(messageFormat, messageArguments);
    }


    /// <summary>
    /// Validates that the specified collection is not empty.
    /// </summary>
    /// <typeparam name="TItem">
    /// The type of the item.
    /// </typeparam>
    /// <param name="collection">
    /// The collection to validate.
    /// </param>
    /// <param name="messageFormat">
    /// A composite format <see cref="string"/>.
    /// </param>
    /// <param name="messageArguments">
    /// An array of message arguments to format.
    /// </param>
    /// <exception cref="InvalidOperationException">
    /// <c>Invalid Operation Exception</c>.
    /// </exception>
    [StringFormatMethod("messageFormat")]
    public static void IsNotEmpty<TItem>(
      [NotNull] IEnumerable<TItem> collection, 
      [NotNull] string messageFormat, 
      [CanBeNull] params object[] messageArguments)
    {
      Assert.ArgumentNotNull(collection, "collection");
      Assert.ArgumentNotNull(messageFormat, "messageFormat");

      if (collection.Any())
      {
        return;
      }

      ThrowException(messageFormat, messageArguments);
    }
    

    #endregion


    #region Methods

    /// <summary>
    /// Throws the exception.
    /// </summary>
    /// <param name="messageFormat">
    /// The message format.
    /// </param>
    /// <param name="messageArguments">
    /// The message arguments.
    /// </param>
    /// <exception cref="InvalidOperationException">
    /// <c>Invalid Operation Exception</c>.
    /// </exception>
    private static void ThrowException([NotNull] string messageFormat, [CanBeNull] object[] messageArguments)
    {
      Assert.ArgumentNotNull(messageFormat, "messageFormat");

      string message = string.Format(CultureInfo.InvariantCulture, messageFormat, messageArguments);

      throw new InvalidOperationException(message);
    }

    #endregion
  }
}